import tkinter as tk
from tkinter import ttk, scrolledtext
import serial
import serial.tools.list_ports
import threading


class SerialTool:
    def __init__(self, root):
        self.root = root
        self.serial = None
        self.serial_thread = None
        self.setup_ui()

    def setup_ui(self):
        self.root.title("串口调试助手")
        self.root.geometry("600x400")

        # 串口选择区域
        port_frame = ttk.Frame(self.root)
        port_frame.pack(pady=5, fill=tk.X)

        ttk.Label(port_frame, text="串口:").pack(side=tk.LEFT)
        self.port_combo = ttk.Combobox(port_frame)
        self.port_combo.pack(side=tk.LEFT, padx=5)

        ttk.Label(port_frame, text="波特率:").pack(side=tk.LEFT)
        self.baudrate_combo = ttk.Combobox(port_frame, values=["9600", "19200", "38400", "57600", "115200"])
        self.baudrate_combo.pack(side=tk.LEFT, padx=5)
        self.baudrate_combo.current(0)

        self.connect_btn = ttk.Button(port_frame, text="连接", command=self.toggle_connection)
        self.connect_btn.pack(side=tk.LEFT, padx=5)

        # 接收显示区域
        self.receive_text = scrolledtext.ScrolledText(self.root)
        self.receive_text.pack(pady=5, fill=tk.BOTH, expand=True)

        # 发送区域
        send_frame = ttk.Frame(self.root)
        send_frame.pack(pady=5, fill=tk.X)

        self.send_input = ttk.Entry(send_frame)
        self.send_input.pack(side=tk.LEFT, padx=5, fill=tk.X, expand=True)

        send_btn = ttk.Button(send_frame, text="发送", command=self.send_data)
        send_btn.pack(side=tk.LEFT, padx=5)

        self.refresh_ports()

    def refresh_ports(self):
        ports = [port.device for port in serial.tools.list_ports.comports()]
        self.port_combo['values'] = ports
        if ports:
            self.port_combo.current(0)

    def toggle_connection(self):
        if self.serial and self.serial.is_open:
            self.disconnect_serial()
            self.connect_btn.config(text="连接")
        else:
            if self.connect_serial():
                self.connect_btn.config(text="断开")

    def connect_serial(self):
        port = self.port_combo.get()
        baudrate = int(self.baudrate_combo.get())

        try:
            self.serial = serial.Serial(port, baudrate, timeout=1)
            self.serial_thread = threading.Thread(target=self.read_serial)
            self.serial_thread.daemon = True
            self.serial_thread.start()
            return True
        except Exception as e:
            self.append_received_data(f"连接失败: {str(e)}")
            return False

    def read_serial(self):
        while self.serial and self.serial.is_open:
            try:
                data = self.serial.readline().decode('utf-8').strip()
                if data:
                    self.root.after(0, self.append_received_data, data)
            except:
                pass

    def disconnect_serial(self):
        if self.serial and self.serial.is_open:
            self.serial.close()

    def send_data(self):
        if self.serial and self.serial.is_open:
            data = self.send_input.get()
            self.serial.write((data + '\r\n').encode('utf-8'))
            self.append_received_data(f"发送: {data}")
            self.send_input.delete(0, tk.END)

    def append_received_data(self, text):
        self.receive_text.insert(tk.END, text + '\n')
        self.receive_text.see(tk.END)

    def on_closing(self):
        self.disconnect_serial()
        self.root.destroy()


def __main__():
    root = tk.Tk()
    app = SerialTool(root)
    root.protocol("WM_DELETE_WINDOW", app.on_closing)
    root.mainloop()


if __name__ == "__main__":
    __main__()
